home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 3: Developer Tools / Linux Cubed Series 3 - Developer Tools.iso / devel / lang / c / c-tools-.000 / c-tools- / c-tools-0.4 / cinfo.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-08-13  |  15.2 KB  |  730 lines

  1. /* cinfo.c -- A C library information tool.
  2.    Copyright (C) 1995 Sandro Sigala - <sansig@freenet.hut.fi> */
  3.  
  4. /* $Id: cinfo.c,v 1.29 1995/08/12 16:59:21 sandro Exp $ */
  5.  
  6. /* This program is free software; you can redistribute it and/or modify
  7.    it under the terms of the GNU General Public License as published by
  8.    the Free Software Foundation; either version 2 of the License, or
  9.    (at your option) any later version.
  10.  
  11.    This program is distributed in the hope that it will be useful,
  12.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.    GNU General Public License for more details.
  15.  
  16.    You should have received a copy of the GNU General Public License
  17.    along with this program; if not, write to the Free Software
  18.    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
  19.  
  20.  
  21. /*
  22.  * To do:
  23.  *  - add a description to all symbols
  24.  *  - add an example program to all symbols
  25.  */
  26.  
  27. #ifndef DEFAULT_SEARCH_PATH
  28. #define DEFAULT_SEARCH_PATH "/usr/lib/cinfo"
  29. #endif
  30.  
  31. #include <ctype.h>
  32. #include <stdio.h>
  33. #include <stdlib.h>
  34. #include <string.h>
  35.  
  36. #include <getopt.h>
  37.  
  38. #include "misc.h"
  39. #include "cinfolib.h"
  40.  
  41. #include "version.h"
  42.  
  43. static FILE *output_file;
  44.  
  45. #define MAX_INCLUDE_DEEP 128
  46.  
  47. static int debug = 0;
  48.  
  49. static struct library_entry *library_head = NULL;
  50. static char current_library[128];
  51. static char current_header[128];
  52. static int library_ok = 0, header_ok = 0;
  53.  
  54. enum { LIBRARY, HEADER, SYMBOL, STRING, INCLUDE };
  55.  
  56. static struct
  57. { char *file_name; int lineno; FILE *file; } include_stack[MAX_INCLUDE_DEEP];
  58.  
  59. static int include_stack_idx = 0;
  60.  
  61. static FILE *current_file;
  62. static char current_file_name[128];
  63. static int lineno = 1;
  64.  
  65. void
  66. include_enter (void)
  67. {
  68.     if (debug)
  69.     fprintf (stderr, "debug: entering include level %d\n",
  70.          include_stack_idx + 1);
  71.  
  72.     include_stack[include_stack_idx].file = current_file;
  73.     include_stack[include_stack_idx].file_name =
  74.     xmalloc (strlen (current_file_name) + 1);
  75.     strcpy (include_stack[include_stack_idx].file_name, current_file_name);
  76.     include_stack[include_stack_idx++].lineno = lineno;
  77. }
  78.  
  79. void
  80. include_leave (void)
  81. {
  82.     if (debug)
  83.     fprintf (stderr, "debug: leaving include level %d (%s %d)\n",
  84.          include_stack_idx, current_file_name, lineno);
  85.  
  86.     current_file = include_stack[--include_stack_idx].file;
  87.     strcpy (current_file_name, include_stack[include_stack_idx].file_name);
  88.     free (include_stack[include_stack_idx].file_name);
  89.     lineno = include_stack[include_stack_idx].lineno;
  90. }
  91.  
  92. static char charbuffer[36];
  93. static int buffindex = 0;
  94.  
  95. #define xgetc() \
  96.     (buffindex ? charbuffer[--buffindex] : getc (current_file))
  97.  
  98. #define xungetc(c) \
  99.     charbuffer[buffindex++] = c
  100.  
  101. static char *token_buffer;
  102.  
  103. static int maxtoken;
  104.  
  105. static void
  106. init_lex (void)
  107. {
  108.     maxtoken = 40;
  109.     token_buffer = (char *) xmalloc (maxtoken + 1);
  110. }
  111.  
  112. static void
  113. done_lex (void)
  114. {
  115.     free (token_buffer);
  116. }
  117.  
  118. static char *
  119. extend_token_buffer (char *p)
  120. {
  121.     int offset = p - token_buffer;
  122.  
  123.     maxtoken = maxtoken * 2 + 10;
  124.     token_buffer = (char *) xrealloc (token_buffer, maxtoken + 2);
  125.  
  126.     return token_buffer + offset;
  127. }
  128.  
  129.  
  130. static void
  131. error (char *s)
  132. {
  133.     fprintf (stderr, "%s:%d: %s\n", current_file_name, lineno, s);
  134.     exit (1);
  135. }
  136.  
  137. static int
  138. gettoken (void)
  139. {
  140.     int c, c1, err = 0;
  141.     while ((c = xgetc ()) == ' ' ||
  142.        c == '\011' || c == '\013' || c == '\014' || c == '\015')
  143.     ;
  144.  
  145.     if (c == EOF)
  146.     return c;
  147.     else if (c == '\n')
  148.     {
  149.     lineno++; 
  150.     return (gettoken ());
  151.     }
  152.     else if (c == '#')
  153.     {
  154.     while ((c = xgetc ()) != EOF && c != '\n')
  155.         ;
  156.     lineno++;
  157.     return (gettoken ());
  158.     }
  159.     else if (c == ';')
  160.     return ';';
  161.     else if (c == '"')
  162.     {
  163.     char *p = token_buffer;
  164.  
  165.     while ((c = xgetc ()) != EOF)
  166.     {
  167.         if (p >= token_buffer + maxtoken)
  168.         p = extend_token_buffer (p);
  169.  
  170.         if (c == '"')
  171.         break;
  172.         else if (c == '\n')
  173.         {
  174.         lineno++;
  175.         *p++ = c;
  176.         }
  177.         else if (c == '\\')
  178.         {
  179.         if ((c1 = xgetc ()) == '\n')
  180.             lineno++;
  181.         else
  182.             *p++ = c1;
  183.         }
  184.         else
  185.         *p++ = c;
  186.     }
  187.  
  188.     *p = '\0';
  189.  
  190.     return STRING;
  191.     }
  192.     else if (c == '.')
  193.     {
  194.     int i = 0;
  195.     char buf[128];
  196.  
  197.     c = xgetc ();
  198.  
  199.     if (c == 'l')
  200.     {
  201.         buf[i++] = 'l';
  202.         if ((buf[i++] = xgetc ()) == 'i' &&
  203.         (buf[i++] = xgetc ()) == 'b' &&
  204.         (buf[i++] = xgetc ()) == 'r' &&
  205.         (buf[i++] = xgetc ()) == 'a' &&
  206.         (buf[i++] = xgetc ()) == 'r' &&
  207.         (buf[i++] = xgetc ()) == 'y')
  208.         return LIBRARY;
  209.         else err = 1;
  210.     }
  211.     else if (c == 'h')
  212.     {
  213.         buf[i++] = 'i';
  214.         if ((buf[i++] = xgetc ()) == 'e' &&
  215.         (buf[i++] = xgetc ()) == 'a' &&
  216.         (buf[i++] = xgetc ()) == 'd' &&
  217.         (buf[i++] = xgetc ()) == 'e' &&
  218.         (buf[i++] = xgetc ()) == 'r')
  219.         return HEADER;
  220.         else err = 1;
  221.     }
  222.     else if (c == 's')
  223.     {
  224.         buf[i++] = 's';
  225.         if ((buf[i++] = xgetc ()) == 'y' &&
  226.         (buf[i++] = xgetc ()) == 'm' &&
  227.         (buf[i++] = xgetc ()) == 'b' &&
  228.         (buf[i++] = xgetc ()) == 'o' &&
  229.         (buf[i++] = xgetc ()) == 'l')
  230.         return SYMBOL;
  231.         else err = 1;
  232.     }
  233.     else if (c == 'i')
  234.     {
  235.         buf[i++] = 'i';
  236.         if ((buf[i++] = xgetc ()) == 'n' &&
  237.         (buf[i++] = xgetc ()) == 'c' &&
  238.         (buf[i++] = xgetc ()) == 'l' &&
  239.         (buf[i++] = xgetc ()) == 'u' &&
  240.         (buf[i++] = xgetc ()) == 'd' &&
  241.         (buf[i++] = xgetc ()) == 'e')
  242.         return INCLUDE;
  243.         else err = 1;
  244.     }
  245.  
  246.     if (err)
  247.     {
  248.         char buf1[64];
  249.         if (buf[i-1] == '\n')
  250.         i--;
  251.         buf[i] = '\0';
  252.         sprintf (buf1, "invalid `.%s' directive", buf);
  253.         error (buf1);
  254.     }
  255.     error ("invalid directive");
  256.     }
  257.     error ("unexpected character");
  258.     return 0;
  259. }
  260.  
  261. static int opt_lib = 0;
  262.  
  263. static void
  264. parse (void)
  265. {
  266.     int tk;
  267.     while (1)
  268.     {
  269.     if ((tk = gettoken ()) == EOF)
  270.     {
  271.         fclose (current_file);
  272.         if (include_stack_idx < 1)
  273.         return;
  274.  
  275.         include_leave ();
  276.  
  277.         continue;
  278.     }
  279.  
  280.     switch (tk)
  281.     {
  282.     case LIBRARY:
  283.     {
  284.         struct library_entry *lp;
  285.         char buf[128];
  286.  
  287.         if ((tk = gettoken ()) != STRING)
  288.         error ("expected name");
  289.         if (strlen (token_buffer) == 0)
  290.         error ("bad name");
  291.  
  292.         strcpy (current_library, token_buffer);
  293.  
  294.         if ((tk = gettoken ()) == STRING)
  295.         {
  296.         if (strlen (token_buffer) == 0)
  297.             error ("bad description");
  298.         }
  299.         else if (tk != ';')
  300.         error ("expected ';' or description after directive");
  301.  
  302.         if (tk == STRING)
  303.         cinfo_compact_info (buf, current_library, token_buffer, 0, 0);
  304.         else
  305.         cinfo_compact_info (buf, current_library, 0, 0, 0);
  306.  
  307.         lp = cinfo_build_library_entry (buf);
  308.  
  309.         if (library_head == NULL)
  310.         library_head = lp;
  311.         else
  312.         cinfo_add_library_to_list (library_head, lp);
  313.  
  314.         library_ok = 1;
  315.  
  316.         break;
  317.     }
  318.  
  319.     case HEADER:
  320.     {
  321.         struct library_entry *lp;
  322.         struct header_entry *hp;
  323.         char buf[128];
  324.  
  325.         if ((tk = gettoken ()) != STRING)
  326.         error ("expected name");
  327.         if (strlen (token_buffer) == 0)
  328.         error ("bad name");
  329.  
  330.         strcpy (current_header, token_buffer);
  331.  
  332.         if ((tk = gettoken ()) == STRING)
  333.         {
  334.         if (strlen (token_buffer) == 0)
  335.             error ("bad description");
  336.         }
  337.         else if (tk != ';')
  338.         error ("expected ';' or description after directive");
  339.  
  340.         if (library_ok == 0)
  341.         error ("unset library name");
  342.  
  343.         if ((lp = cinfo_search_library (library_head,
  344.                         current_library)) == NULL)
  345.         error ("internal fault (1)");
  346.  
  347.         if (tk == STRING)
  348.         cinfo_compact_info (buf, current_header, token_buffer, 0, 0);
  349.         else
  350.         cinfo_compact_info (buf, current_header, 0, 0, 0);
  351.  
  352.         hp = cinfo_build_header_entry (buf);
  353.  
  354.         if (lp->head == NULL)
  355.         lp->head = hp;
  356.         else
  357.         cinfo_add_header_to_list (lp->head, hp);
  358.  
  359.         header_ok = 1;
  360.  
  361.         break;
  362.     }
  363.  
  364.     case SYMBOL:
  365.     {
  366.         struct library_entry *lp;
  367.         struct header_entry *hp;
  368.         struct symbol_entry *sp;
  369.         char *symbol_name, *symbol_type, *symbol_proto, *name;
  370.  
  371.         if ((tk = gettoken ()) != STRING)
  372.         error ("expected name after directive");
  373.         if (strlen (token_buffer) == 0)
  374.         error ("bad name");
  375.         symbol_name = (char *) xmalloc (strlen (token_buffer) + 1);
  376.         strcpy (symbol_name, token_buffer);
  377.  
  378.         if ((tk = gettoken ()) != STRING)
  379.         error ("expected type string after symbol name");
  380.         if (strlen (token_buffer) == 0 ||
  381.         (strcmp (token_buffer, "func") != 0 &&
  382.          strcmp (token_buffer, "macro") != 0 &&
  383.          strcmp (token_buffer, "struct") != 0 &&
  384.          strcmp (token_buffer, "union") != 0 &&
  385.          strcmp (token_buffer, "type") != 0))
  386.         error ("bad type");
  387.  
  388.         symbol_type = (char *) xmalloc (strlen (token_buffer) + 1);
  389.         strcpy (symbol_type, token_buffer);
  390.  
  391.         if ((tk = gettoken ()) != STRING)
  392.         error ("expected prototype or definition after type");
  393.         if (strlen (token_buffer) == 0)
  394.         error ("bad prototype or definition");
  395.  
  396.         symbol_proto = (char *) xmalloc (strlen (token_buffer) + 1);
  397.         strcpy (symbol_proto, token_buffer);
  398.  
  399.         if ((tk = gettoken ()) != ';')
  400.         error ("expected ';' after directive");
  401.  
  402.         name = (char *) xmalloc (strlen (symbol_name) +
  403.                      strlen (symbol_type) +
  404.                      strlen (symbol_proto) + 20);
  405.  
  406.         cinfo_compact_info (name, symbol_name,
  407.                 symbol_type, symbol_proto, 0);
  408.  
  409.         free (symbol_name);
  410.         free (symbol_type);
  411.         free (symbol_proto);
  412.  
  413.         if (library_ok == 0)
  414.         error ("unset library name");
  415.  
  416.         if (header_ok == 0)
  417.         error ("unset header name");
  418.  
  419.         lp = cinfo_search_library (library_head, current_library);
  420.  
  421.         if (lp == NULL)
  422.         error ("internal fault (2)");
  423.  
  424.         hp = cinfo_search_header (lp->head, current_header);
  425.  
  426.         if (hp == NULL)
  427.         error ("internal fault (3)");
  428.  
  429.         sp = cinfo_build_symbol_entry (name);
  430.  
  431.         free (name);
  432.  
  433.         if (hp->head == NULL)
  434.         hp->head = sp;
  435.         else
  436.         cinfo_add_symbol_to_list (hp->head, sp);
  437.  
  438.         break;
  439.     }
  440.  
  441.     case INCLUDE:
  442.     {
  443.         char buf[128];
  444.  
  445.         if ((tk = gettoken ()) != STRING)
  446.         error ("expected string");
  447.         if (strlen (token_buffer) == 0)
  448.         error ("bad string");
  449.  
  450.         strcpy (buf, token_buffer);
  451.  
  452.         if (include_stack_idx + 1 >= MAX_INCLUDE_DEEP)
  453.         error ("max include deep encourred");
  454.  
  455.         if ((tk = gettoken ()) != ';')
  456.         error ("expected ';' after directive");
  457.  
  458.         include_enter ();
  459.  
  460.         strcpy (current_file_name, buf);
  461.  
  462.         lineno = 1;
  463.  
  464.         if (debug)
  465.         fprintf (stderr, "debug: looking for \"%s\"...\n",
  466.              current_file_name);
  467.  
  468.         if ((current_file = fopen (current_file_name, "r")) == NULL)
  469.         {
  470.         strcpy (current_file_name, DEFAULT_SEARCH_PATH);
  471.         strcat (current_file_name, "/");
  472.         strcat (current_file_name, buf);
  473.  
  474.         if (debug)
  475.             fprintf (stderr, "debug: looking for \"%s\"...\n",
  476.                  current_file_name);
  477.  
  478.         if ((current_file = fopen (current_file_name, "r")) == NULL)
  479.         {
  480.             sprintf (buf, "cannot open include file \"%s\"",
  481.                  current_file_name);
  482.             error (buf);
  483.         }
  484.         }
  485.  
  486.         break;
  487.     }
  488.  
  489.     case STRING:
  490.         error ("unexpected string");
  491.     }
  492.     }
  493. }
  494.  
  495. static int opt_readable_output = 1;
  496.  
  497. static void
  498. document_symbol_list (struct symbol_entry *list, char *header)
  499. {
  500.     struct symbol_entry *p = list;
  501.     char *buf1, *buf2, *buf3;
  502.  
  503.     while (p != NULL)
  504.     {
  505.     buf1 = (char *) xmalloc (strlen (p->name) + 1);
  506.     buf2 = (char *) xmalloc (strlen (p->name) + 1);
  507.     buf3 = (char *) xmalloc (strlen (p->name) + 1);
  508.  
  509.     cinfo_decompact_info (p->name, buf1, buf2, buf3, NULL);
  510.  
  511.     if (opt_readable_output)
  512.     {
  513.         if (strcmp (buf2, "macro") == 0)
  514.         fprintf (output_file, "symbol %s: macro.\n", buf1);
  515.         else if (strcmp (buf2, "func") == 0)
  516.         fprintf (output_file, "symbol %s: function.\n", buf1);
  517.         else if (strcmp (buf2, "struct") == 0)
  518.         fprintf (output_file, "symbol %s: structure.\n", buf1);
  519.         else if (strcmp (buf2, "union") == 0)
  520.         fprintf (output_file, "symbol %s: union.\n", buf1);
  521.         else if (strcmp (buf2, "type") == 0)
  522.         fprintf (output_file, "symbol %s: defined type.\n", buf1);
  523.  
  524.         fprintf (output_file, "\n");
  525.  
  526.         if (buf3[0] == '$')
  527.         fprintf (output_file, "%s\n", buf3 + 1);
  528.         else
  529.         {
  530.         fprintf (output_file, "#include <%s>\n\n", header);
  531.         fprintf (output_file, "%s\n\n", buf3);
  532.         }
  533.     }
  534.     else
  535.     {
  536.         fprintf (output_file, "!%s \"%s\"\n", buf2, buf1);
  537.  
  538.         if (buf3[0] == '$')
  539.         fprintf (output_file, "$\"%s\"\n", buf3 + 1);
  540.         else
  541.         fprintf (output_file, "$\"%s\"\n", buf3);
  542.     }
  543.  
  544.     free (buf1);
  545.     free (buf2);
  546.     free (buf3);
  547.  
  548.     p = p->next;
  549.     }
  550. }
  551.  
  552. static void
  553. document_header_list (struct header_entry *list)
  554. {
  555.     struct header_entry *p = list;
  556.     char *buf;
  557.  
  558.     while (p != NULL)
  559.     {
  560.     buf = (char *) xmalloc (strlen (p->name) + 1);
  561.  
  562.     cinfo_decompact_info_first (p->name, buf);
  563.  
  564.     if (opt_readable_output)
  565.         fprintf (output_file, "header \"%s\".\n", buf);
  566.     else
  567.         fprintf (output_file, "!header \"%s\"\n", buf);
  568.  
  569.     if (p->head != NULL)
  570.         document_symbol_list (p->head, buf);
  571.  
  572.     free (buf);
  573.  
  574.     p = p->next;
  575.     }
  576. }
  577.  
  578. static void
  579. document_library_list (struct library_entry *list)
  580. {
  581.     struct library_entry *p = list;
  582.     char *buf;
  583.  
  584.     while (p != NULL)
  585.     {
  586.     buf = (char *) xmalloc (strlen (p->name) + 1);
  587.  
  588.     cinfo_decompact_info_first (p->name, buf);
  589.  
  590.     if (opt_readable_output)
  591.         fprintf (output_file, "In library \"%s\", ", buf);
  592.     else
  593.         fprintf (output_file, "!library \"%s\"\n", buf);
  594.  
  595.     free (buf);
  596.  
  597.     if (p->head != NULL)
  598.         document_header_list (p->head);
  599.  
  600.     p = p->next;
  601.     }
  602. }
  603.  
  604. void
  605. helppage (char *progname)
  606. {
  607.     fprintf (stderr, "\
  608. %s %s - c-tools %s - Copyright (C) 1995 Sandro Sigala.\n\
  609. usage: %s [-hm] [-l libfile] [-o outfile] [symbol]\n\
  610.        -h         display this help and exit\n\
  611.        -m         make output more program-parseable\n\
  612.        -l libfile specify the library to load instead the default\n\
  613.        -o outfile specify the output file instead the standard output\n\
  614. ",
  615.          progname, VERSION_CINFO, VERSION_CTOOLS, progname);
  616.     exit (0);
  617. }
  618.  
  619. int
  620. main (int argc, char **argv)
  621. {
  622.     int c;
  623.     struct library_entry *le;
  624.     char output_file_name[128];
  625.     int opt_out = 0;
  626.     char what[128];
  627.  
  628.     strcpy (current_file_name, "cinfo.lib");
  629.     strcpy (output_file_name, "stdout");
  630.  
  631.     while (1)
  632.     {
  633.     c = getopt (argc, argv, "l:o:dhm");
  634.     if (c == EOF)
  635.         break;
  636.  
  637.     switch (c)
  638.     {
  639.     case 'l':
  640.         opt_lib = 1;
  641.         strcpy (current_file_name, optarg);
  642.         break;
  643.  
  644.     case 'o':
  645.         strcpy (output_file_name, optarg);
  646.         opt_out = 1;
  647.         break;
  648.  
  649.     case 'd':
  650.         debug = 1;
  651.         break;
  652.  
  653.     case 'm':
  654.         opt_readable_output = 0;
  655.         break;
  656.  
  657.     case 'h':
  658.     case '?':
  659.         helppage (argv[0]);
  660.         break;
  661.     }
  662.     }
  663.  
  664.     if (argc - optind != 1)
  665.     helppage (argv[0]);
  666.     strcpy (what, argv[optind]);
  667.  
  668.     if (debug)
  669.     fprintf (stderr, "debug: looking for \"%s\"...\n", current_file_name);
  670.  
  671.     if ((current_file = fopen (current_file_name, "r")) == NULL)
  672.     {
  673.     if (opt_lib == 1)
  674.     {
  675.         fprintf (stderr, "%s: cannot open library file \"%s\"\n",
  676.              argv[0], current_file_name);
  677.         exit (1);
  678.     }
  679.     else
  680.     {
  681.         strcpy (current_file_name, DEFAULT_SEARCH_PATH);
  682.         strcat (current_file_name, "/cinfo.lib");
  683.         if (debug)
  684.         fprintf (stderr, "debug: looking for \"%s\"...\n",
  685.              current_file_name);
  686.         
  687.         if ((current_file = fopen (current_file_name, "r")) == NULL)
  688.         {
  689.         fprintf (stderr, "%s: cannot open library file \"%s\"\n",
  690.              argv[0], current_file_name);
  691.         exit (1);
  692.         }
  693.     }
  694.     }
  695.  
  696.     output_file = stdout;
  697.  
  698.     if (opt_out)
  699.     {
  700.     if ((output_file = fopen (output_file_name, "w")) == NULL)
  701.     {
  702.         fprintf (stderr, "%s: cannot open output file\n", argv[0]);
  703.         exit (1);
  704.     }
  705.     }
  706.  
  707.     lineno = 1;
  708.  
  709.     init_lex (); /* initialize the lexical analizer */
  710.  
  711.     parse ();
  712.  
  713.     done_lex ();
  714.  
  715.  
  716.     if (debug)
  717.     fprintf (stderr, "debug: searching...\n");
  718.  
  719.     le = cinfo_query_library_list_about_symbol (library_head, what);
  720.  
  721.     if (debug)
  722.     fprintf (stderr, "debug: outputting...\n");
  723.  
  724.     document_library_list (le);
  725.  
  726.     return 0;
  727. }
  728.  
  729. /* cinfo.c ends here */
  730.